package com.example.casserver.controller;

import com.example.casserver.dto.LoginRequest;
import com.example.casserver.dto.LoginResponse;
import com.example.casserver.entity.User;
import com.example.casserver.model.ServiceTicket;
import com.example.casserver.model.TicketGrantingTicket;
import com.example.casserver.service.LogoutNotificationService;
import com.example.casserver.service.TicketService;
import com.example.casserver.service.UserService;
import com.example.casserver.util.JwtUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

/**
 * CAS认证控制器
 * 实现CAS协议的主要接口，包括登录、票据验证和登出功能
 */
@Controller
@RequestMapping("/")
public class CasController {

    private static final Logger logger = LoggerFactory.getLogger(CasController.class);

    private final TicketService ticketService;
    private final UserService userService;
    private final PasswordEncoder passwordEncoder;
    private final JwtUtil jwtUtil;
    private final LogoutNotificationService logoutNotificationService;

    public CasController(TicketService ticketService, UserService userService,
                         PasswordEncoder passwordEncoder, JwtUtil jwtUtil,
                         LogoutNotificationService logoutNotificationService) {
        this.ticketService = ticketService;
        this.userService = userService;
        this.passwordEncoder = passwordEncoder;
        this.jwtUtil = jwtUtil;
        this.logoutNotificationService = logoutNotificationService;
    }

    /**
     * 处理登录请求
     * CAS单点登录的核心入口点：
     * 1. 检查用户是否已有有效TGT（通过CASTGC cookie）
     * 2. 如果有效，自动生成ST并重定向到服务
     * 3. 否则显示登录页面
     */
    @GetMapping("/login")
    public String loginPage(@RequestParam(required = false) String service,
                            @CookieValue(name = "CASTGC", required = false) String tgtId,
                            Model model) {
        // 1. 尝试使用现有TGT自动登录
        if (tgtId != null) {
            TicketGrantingTicket tgt = ticketService.getTicketGrantingTicket(tgtId);

            // 如果TGT有效且有service参数，生成ST并重定向
            if (tgt != null && tgt.isValid() && StringUtils.hasText(service)) {
                ServiceTicket st = ticketService.generateServiceTicket(tgtId, service);
                if (st != null) {
                    registerServiceUrl(st.getUsername(), st.getId(), service);
                    logger.debug("自动登录成功: 用户={}, 服务={}", tgt.getUsername(), service);
                    return "redirect:" + service + "?ticket=" + st.getId();
                }
            }

            // 如果TGT有效但没有service参数，重定向到首页
            if (tgt != null && tgt.isValid() && !StringUtils.hasText(service)) {
                return "redirect:/";
            }
        }

        // 2. 自动登录失败，显示登录页面
        model.addAttribute("service", service);
        return "login";
    }

    /**
     * 显示成功页面
     * 当用户成功登录但没有指定service参数时显示
     */
    @GetMapping("/")
    public String successPage(@CookieValue(name = "CASTGC", required = false) String tgt, Model model) {
        if (tgt != null) {
            TicketGrantingTicket ticket = ticketService.getTicketGrantingTicket(tgt);
            if (ticket != null && ticket.isValid()) {
                model.addAttribute("username", ticket.getUsername());
                return "success";
            }
        }
        return "redirect:/login";
    }

    /**
     * 处理表单登录请求
     * 验证用户凭据，创建TGT，并根据是否有service参数决定重定向目标
     */
    @PostMapping(value = "/login", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    public String formLogin(@RequestParam String username,
                            @RequestParam String password,
                            @RequestParam(required = false) String service,
                            HttpServletResponse response) {
        // 验证用户凭据
        User user = userService.findByUsername(username);
        if (user == null || !passwordEncoder.matches(password, user.getPassword())) {
            return "redirect:/login?error=true" + (service != null ? "&service=" + service : "");
        }

        // 创建TGT并设置cookie
        TicketGrantingTicket tgt = ticketService.createTicketGrantingTicket(username);
        Cookie tgtCookie = new Cookie("CASTGC", tgt.getId());
        tgtCookie.setPath("/");
        tgtCookie.setDomain("localhost");
        tgtCookie.setHttpOnly(true);
        response.addCookie(tgtCookie);

        // 如果有service参数，生成ST并重定向
        if (StringUtils.hasText(service)) {
            ServiceTicket st = ticketService.generateServiceTicket(tgt.getId(), service);
            if (st != null) {
                registerServiceUrl(username, st.getId(), service);
            }
            return "redirect:" + service + "?ticket=" + st.getId();
        }

        return "redirect:/";
    }

    /**
     * 处理JSON格式的登录请求（用于API调用）
     * 验证用户凭据，创建TGT，生成JWT令牌
     */
    @PostMapping(value = "/login", consumes = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public ResponseEntity<LoginResponse> apiLogin(@RequestBody LoginRequest loginRequest,
                                                  HttpServletResponse response) {
        // 验证用户凭据
        User user = userService.findByUsername(loginRequest.getUsername());
        if (user == null || !passwordEncoder.matches(loginRequest.getPassword(), user.getPassword())) {
            return ResponseEntity.ok(new LoginResponse("error", "Invalid username or password", null, null));
        }

        // 生成JWT令牌
        String token = jwtUtil.generateToken(user.getUsername());

        // 创建TGT
        TicketGrantingTicket tgt = ticketService.createTicketGrantingTicket(user.getUsername());
        Cookie tgtCookie = new Cookie("CASTGC", tgt.getId());
        tgtCookie.setPath("/");
        tgtCookie.setDomain("localhost");
        tgtCookie.setHttpOnly(true);
        response.addCookie(tgtCookie);

        // 如果请求中包含service参数，生成服务票据
        if (loginRequest.getService() != null && !loginRequest.getService().isEmpty()) {
            ServiceTicket ticket = ticketService.generateServiceTicket(tgt.getId(), loginRequest.getService());
            if (ticket != null) {
                registerServiceUrl(loginRequest.getUsername(), ticket.getId(), loginRequest.getService());
            }
            String redirectUrl = loginRequest.getService() + "?ticket=" + ticket.getId();
            return ResponseEntity.ok(new LoginResponse("success", token, ticket.getId(), redirectUrl));
        }

        return ResponseEntity.ok(new LoginResponse("success", token, null, null));
    }

    /**
     * 验证服务票据（CAS 1.0协议）
     * 返回简单的文本响应：yes\n用户名 或 no\n\n
     */
    @GetMapping("/validate")
    @ResponseBody
    public ResponseEntity<String> validateTicket(@RequestParam String ticket, @RequestParam String service) {
        ServiceTicket serviceTicket = ticketService.validateTicket(ticket);
        if (serviceTicket != null && service.equals(serviceTicket.getService())) {
            return ResponseEntity.ok("yes\n" + serviceTicket.getUsername());
        }
        return ResponseEntity.ok("no\n\n");
    }

    /**
     * 验证服务票据（CAS 2.0协议）
     * 返回XML格式的验证响应，包含用户详细信息
     */
    @GetMapping("/serviceValidate")
    @ResponseBody
    public ResponseEntity<String> serviceValidate(@RequestParam String ticket, @RequestParam String service) {
        ServiceTicket serviceTicket = ticketService.validateTicket(ticket);
        if (serviceTicket != null && service.equals(serviceTicket.getService())) {
            User user = userService.findByUsername(serviceTicket.getUsername());
            String response = String.format("""
                    <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
                        <cas:authenticationSuccess>
                            <cas:user>%s</cas:user>
                            <cas:attributes>
                                <cas:email>%s</cas:email>
                                <cas:enabled>%s</cas:enabled>
                            </cas:attributes>
                        </cas:authenticationSuccess>
                    </cas:serviceResponse>
                    """, user.getUsername(), user.getEmail(), user.getEnabled());
            return ResponseEntity.ok()
                    .contentType(MediaType.APPLICATION_XML)
                    .body(response);
        }

        String response = """
                <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
                    <cas:authenticationFailure code="INVALID_TICKET">
                        Ticket not recognized or expired
                    </cas:authenticationFailure>
                </cas:serviceResponse>
                """;
        return ResponseEntity.ok()
                .contentType(MediaType.APPLICATION_XML)
                .body(response);
    }

    /**
     * 验证服务票据（CAS 3.0协议）
     * 返回XML格式的验证响应，包含更丰富的用户属性
     */
    @GetMapping("/p3/serviceValidate")
    @ResponseBody
    public ResponseEntity<String> p3ServiceValidate(@RequestParam String ticket,
                                                    @RequestParam String service,
                                                    @RequestParam(required = false) String pgtUrl) {
        ServiceTicket serviceTicket = ticketService.validateTicket(ticket);
        if (serviceTicket != null && service.equals(serviceTicket.getService())) {
            User user = userService.findByUsername(serviceTicket.getUsername());
            String response = String.format("""
                            <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
                                <cas:authenticationSuccess>
                                    <cas:user>%s</cas:user>
                                    <cas:attributes>
                                        <cas:email>%s</cas:email>
                                        <cas:enabled>%s</cas:enabled>
                                        <cas:authenticationDate>%s</cas:authenticationDate>
                                        <cas:isFromNewLogin>true</cas:isFromNewLogin>
                                    </cas:attributes>
                                </cas:authenticationSuccess>
                            </cas:serviceResponse>
                            """, user.getUsername(), user.getEmail(), user.getEnabled(),
                    serviceTicket.getCreatedAt().toString());
            return ResponseEntity.ok()
                    .contentType(MediaType.APPLICATION_XML)
                    .body(response);
        }

        String response = """
                <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
                    <cas:authenticationFailure code="INVALID_TICKET">
                        Ticket not recognized or expired
                    </cas:authenticationFailure>
                </cas:serviceResponse>
                """;
        return ResponseEntity.ok()
                .contentType(MediaType.APPLICATION_XML)
                .body(response);
    }

//    /**
//     * 手动处理登出请求（必须要做的缺一不可：1、销毁全局会话。2、向所有注册的客户端发送登出请求。3、重定向到指定的服务页面。）
//     * 使TGT失效，清除cookie，并通知已注册的服务
//     */
//    @GetMapping("/logout")
//    public String logout(@RequestParam(required = false) String service,
//                         @CookieValue(name = "CASTGC", required = false) String tgt,
//                         HttpServletResponse response) {
//        if (tgt != null) {
//            TicketGrantingTicket ticket = ticketService.getTicketGrantingTicket(tgt);
//            if (ticket != null) {
//                // 发送登出通知
//                logoutNotificationService.notifyLogout(ticket.getUsername());
//            }
//
//            // 使TGT失效
//            ticketService.invalidateTicketGrantingTicket(tgt);
//            Cookie tgtCookie = new Cookie("CASTGC", null);
//            tgtCookie.setPath("/");
//            tgtCookie.setMaxAge(0);
//            response.addCookie(tgtCookie);
//        }
//
//        // 清除Spring Security上下文
//        SecurityContextHolder.clearContext();
//
//        // 如果提供了service参数，重定向到service
//        if (StringUtils.hasText(service)) {
//            return "redirect:" + service;
//        }
//
//        return "logout";
//    }

    /**
     * 注册服务URL
     * 用于记录用户访问的服务，以便在用户登出时通知
     */
    private void registerServiceUrl(String username, String ticket, String service) {
        logoutNotificationService.registerService(username, ticket, service);
    }
} 